#ifndef _TJDARRAY742011_H_
#define _TJDARRAY742011_H_

template <class T>
class DArray
{
public:
	typedef T Type;
public:
	DArray() { initBuffer(); }

	DArray(const DArray& other);

	~DArray();

	bool equals(const DArray& other) const;

	void reset();

	void add(const Type& ele);

	void remove(int index);

	Type& operator[](int index);

	const Type& operator[](int index) const;

	int size() const { return elementNum; }

	bool setBufferSize(int new_size);

	int getBufferSize() const { return bufferSize; }

private:
	void increaseBuffer();

	void initBuffer();

private:
	Type* buffer;
	int bufferSize;
	int elementNum;
};

template<class T>
DArray<T>::DArray(const DArray<T>& other) :
{
	buffer = new Type[other.size()];
	
	elementNum = other.elementNum;
	for (int i = 0; i < elementNum; i ++) {
		buffer[i] = other.buffer[i];
	}
}

template <class T>
bool DArray<T>::equals(const DArray<T>& other) const {
	if (elementNum == other.elementNum) {
		for (int i = 0; i < elementNum; i ++) {
			if (buffer[i] != other.buffer[i]) {
				return false;
			}
		}
		return true;
	}

	return false;
}

template<class T>
DArray<T>::~DArray() {
	reset();
}

template <class T>
void DArray<T>::add(const T& ele) {
	if (elementNum >= bufferSize) {
		increaseBuffer();
	}

	buffer[elementNum ++] = ele;
}

template <class T>
void DArray<T>::remove(int index) {
	// assert(index < elementNum);
	if (index >= elementNum) return;

	memmove((void*)(buffer + index), 
		(void*)(buffer + index + 1), 
		(elementNum - index - 1) * sizeof(Type));

	elementNum --;
}

template <class T>
void DArray<T>::reset() {
	delete [] buffer;

	buffer = NULL;
	bufferSize = 0;
	elementNum = 0;
}

template <class T>
void DArray<T>::initBuffer() {
	bufferSize = 64;
	elementNum = 0;
	buffer = new Type[bufferSize];
}

template <class T>
bool DArray<T>::setBufferSize(int new_size) {
	if (new_size < bufferSize) return false;

	Type* new_buffer = new Type[new_size];

	memcpy(new_buffer, buffer, sizeof(Type) * elementNum);

	bufferSize = new_size;

	delete[] buffer;
	buffer = new_buffer;
	
	return true;
}

template <class T>
const T& DArray<T>::operator [](int index) const {
	// assert(index < elementNum)
	return buffer[index];
}

template <class T>
T& DArray<T>::operator [](int index) {
	if (index > bufferSize - 1) {
		while (index > bufferSize - 1) {
			bufferSize *= 2;
		}
		setBufferSize(bufferSize);
	}

	if (index > elementNum - 1) {
		// set the elements before index to a sound value
		for (int i = elementNum; i < index; i ++) {
			buffer[i] = 0;
		}
		elementNum = index + 1;
	}
	return buffer[index];
}

template <class T>
void DArray<T>::increaseBuffer() {
	int new_size = bufferSize * 2;
	
	setBufferSize(new_size);
}
#endif //_TJDARRAY742011_H_